package com.qding.park.manager.service.core.facade.impl.common;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.qding.park.common.core.cache.service.CacheServiceFacade;
import com.qding.park.common.core.exceptions.BaseException;
import com.qding.park.common.core.exceptions.ExceptionMessage;
import com.qding.park.common.core.exceptions.IExceptionHandle;
import com.qding.park.common.core.exceptions.business.manager.service.ServiceCoreException;
import com.qding.park.common.utils.DateUtils;
import com.qding.park.common.utils.ListUtil;
import com.qding.park.common.utils.string.StringUtil;
import com.qding.park.manager.adapter.factory.AdapterParkProxyFactory;
import com.qding.park.manager.cache.ParkCacheInter;
import com.qding.park.manager.cache.UserCacheInter;
import com.qding.park.manager.common.pojo.ParkDataResult;
import com.qding.park.manager.facade.core.service.common.ParkCommonFacade;
import com.qding.park.manager.facade.core.service.entity.ParkStatu;
import com.qding.park.manager.pojo.TbCar;
import com.qding.park.manager.pojo.TbParkingrule;
import com.qding.park.manager.pojo.TbParkspace;
import com.qding.park.manager.pojo.TbUserInfo;
import com.qding.park.manager.pojo.enums.BusyNameTypeEnum;
import com.qding.park.manager.pojo.enums.CarTypeEnum;
import com.qding.park.manager.pojo.enums.ParkStatuEnum;
import com.qding.park.manager.pojo.enums.UserTypeEnum;
import com.qding.park.manager.service.core.atomic.distributed.UserDBAtomic;
import com.qding.park.manager.service.core.biz.ParkBiz;
import com.qding.park.manager.service.core.config.ExpiratAdvanceWarn;
import com.qding.park.manager.service.core.config.ParkTempStopNumReserve;
import com.qding.park.manager.service.core.mapper.TbCarMapper;
import com.qding.park.manager.service.core.mapper.TbParkingruleMapper;
import com.qding.park.manager.service.core.mapper.TbParkspaceMapper;
import com.qding.park.target.common.adapter.ParkAdapter;
import com.qding.park.target.common.entity.AdParkConnStatu;
import com.qding.park.target.common.entity.AdParkInfo;


@Service("parkCommonFacade")
public class ParkCommonFacadeImpl implements ParkCommonFacade {

    private static final Logger _log = LoggerFactory.getLogger(ParkCommonFacadeImpl.class);
    @Autowired
    private ParkBiz parkBiz;
    
    @Autowired
    private UserCacheInter userCacheInter;
    
    @Autowired
    private TbParkspaceMapper tbParkspaceMapper;
    
    @Autowired
    private TbParkingruleMapper tbParkingruleMapper;
    
    @Autowired
    private ParkCacheInter parkCacheInter;
    
    @Autowired
    private AdapterParkProxyFactory adapterParkProxyFactory;
    
    @Autowired
    private IExceptionHandle exceptionHandle;
    
    @Autowired
    private UserDBAtomic userDBAtomic;
    
    @Autowired
    private TbCarMapper tbCarMapper;
    
    @Autowired
    private CacheServiceFacade cacheServiceFacade;

    
    @Override
    public TbParkspace getParkInfoByParkId(int parkId) {
        TbParkspace tbParkspace = parkBiz.getParkInfoByParkId(parkId);
        return tbParkspace;
    }


    @Override
    public ParkDataResult listall(String tel, String bjuserid, String bjprojectId) throws BaseException {
        String userIdstr = userCacheInter.bjuserId2userId(bjuserid);
        List<TbParkspace> parkList = new ArrayList<TbParkspace>();
        if (StringUtils.isBlank(userIdstr) && !StringUtils.isBlank(bjprojectId)) {
            String[] paramsArray = bjprojectId.split(",");
            parkList = tbParkspaceMapper.listAllByProject(paramsArray);
        }

        if (ListUtil.isEmpty(parkList) && !StringUtils.isBlank(userIdstr)) {
            int userId = Integer.valueOf(userIdstr);

            parkList = tbParkspaceMapper.queryParksByUserId(userId);

            if (ListUtil.isEmpty(parkList) && !StringUtils.isBlank(bjprojectId)) {
                String[] paramsArray = bjprojectId.split(",");
                parkList = tbParkspaceMapper.listAllByProject(paramsArray);
            }
        }

        List dataList = new ArrayList();
        for (TbParkspace park : parkList) {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("parkId", park.getId());
            map.put("parkName", park.getParkName());
            dataList.add(map);
        }
        ParkDataResult parkDataResult = ParkDataResult.createListDate();
        parkDataResult.putDataOnList(dataList);
        return parkDataResult;
    }
    
    
    /*
     * (非 Javadoc) Description:
     * @see com.qding.park.manager.facade.core.service.ParkFacade#getparkBookRules( int) 流程 从数据库中查询预定规则
     */
    @Override
    public ParkDataResult getParkBookRules(int parkId) throws ServiceCoreException {
        TbParkspace tbParkspace = parkBiz.getParkInfoByParkId(parkId);
        ParkDataResult data = ParkDataResult.createObjDate();
        if (tbParkspace != null) {
            int reservedeposit = tbParkspace.getReservedeposit();
            String reserverContect = tbParkspace.getReserverContect();
            // 预定金额
            data.putDataOnObj("depositExplain", reservedeposit);
            // 预定说明文本
            data.putDataOnObj("reserverContect", reserverContect);
            return data;
        } else {

            throw new ServiceCoreException(ServiceCoreException.TypeEnum.EXCEPTION_NOFIND_PARK.getId(), null,
                    ExceptionMessage.createExceptionMessage(
                            ServiceCoreException.TypeEnum.EXCEPTION_NOFIND_PARK.getDesc(), "",
                            "没有找到　" + parkId + "对应的车场"));
        }

    }


    @Override
    public ParkDataResult getRuleByParkId(int parkId) throws ServiceCoreException {
        

        List<TbParkingrule> tbParkingrules = tbParkingruleMapper.queryRuleByParkId(parkId);

        if (ListUtil.isEmpty(tbParkingrules)) {
            // 车辆没有停在此车场
            throw new ServiceCoreException(ServiceCoreException.TypeEnum.EXCEPTION_NOTFIND_PARKRULE.getId(), null,
                    ExceptionMessage.createExceptionMessage(
                            ServiceCoreException.TypeEnum.EXCEPTION_NOTFIND_PARKRULE.getDesc(), "没有找到此车场的对庆规则",
                            "parkId:" + parkId));
        }
        
        Map<String, List<TbParkingrule>> tempMap_time = new LinkedHashMap<String, List<TbParkingrule>>();
        for (TbParkingrule rule : tbParkingrules) {
            String key = BusyNameTypeEnum.fromInt(rule.getBusyName()) + rule.getDuringStart() + "-"
                    + rule.getDuringEnd();
            if (tempMap_time.containsKey(key)) {
                // 存在
                tempMap_time.get(key).add(rule);
            } else {
                // 不存在
                List<TbParkingrule> ruleList = new ArrayList<TbParkingrule>();
                tempMap_time.put(key, ruleList);
                tempMap_time.get(key).add(rule);
            }
        }
        
        Map<String, List<TbParkingrule>> tempMap_carType = new LinkedHashMap<String, List<TbParkingrule>>();
        for (TbParkingrule rule : tbParkingrules) {
            String key =CarTypeEnum.fromInt(rule.getCarTypeCode());
            if (tempMap_carType.containsKey(key)) {
                // 存在
                tempMap_carType.get(key).add(rule);
            } else {
                // 不存在
                List<TbParkingrule> ruleList = new ArrayList<TbParkingrule>();
                tempMap_carType.put(key, ruleList);
                tempMap_carType.get(key).add(rule);
            }
        }
        
        List list = new ArrayList();//分时段计费规则
        for(Map.Entry<String, List<TbParkingrule>> entry:tempMap_time.entrySet()){
            Map<String, Object> map = new LinkedHashMap<String, Object>();
            list.add(map);
            List listAll = new ArrayList();
            String key=entry.getKey();
            
            map.put("timeBucket", key);
            map.put("listAll", listAll);
            for(Map.Entry<String, List<TbParkingrule>> entry1:tempMap_carType.entrySet()){
                
                Map<String, Object> map_2 = new LinkedHashMap<String, Object>();
                map_2.put("carType", entry1.getKey());
                listAll.add(map_2);
                List perRule = new ArrayList();
                List inParkRule = new ArrayList();
                List<String> perRule_tag = new ArrayList();
                List<String> inParkRule_tag = new ArrayList();
                for(TbParkingrule  rule:entry1.getValue()){
                    String key_1 = BusyNameTypeEnum.fromInt(rule.getBusyName()) + rule.getDuringStart() + "-"
                            + rule.getDuringEnd();
                    
                    map_2.put("perRule", perRule);
                    map_2.put("inParkRule", inParkRule);
                    if(key_1.equals(key)){
                        Map<String, Object> perRule_1 = new LinkedHashMap<String, Object>();
                        Map<String, Object> inParkRule_1 = new LinkedHashMap<String, Object>();
                        if(!perRule_tag.contains(rule.getPerTime()+":"+rule.getPerCost())){
                            perRule_1.put("perTime",rule.getPerTime());
                            perRule_1.put("perCost", rule.getPerCost());
                            perRule.add(perRule_1);
                            perRule_tag.add(rule.getPerTime()+":"+rule.getPerCost());
                        }
                        if(!inParkRule_tag.contains(rule.getInParkTime()+":"+rule.getInParkTimeCost())){
                            inParkRule_1.put("inParkTime", rule.getInParkTime());
                            inParkRule_1.put("inParkTimeCost", rule.getInParkTimeCost());
                            inParkRule.add(inParkRule_1);
                            inParkRule_tag.add(rule.getInParkTime()+":"+rule.getInParkTimeCost());
                        }
                    
                    }
                    
                    
                }
                
                
            }
        }
        ParkDataResult data = ParkDataResult.createListDate();
        data.putDataOnList(list);
        return data;
    }
    
    @Override
    public ParkStatu getParkStatus(int supplierId, Integer parkId) {
        
        TbParkspace  tbParkspace=parkCacheInter.queryParkSpace(parkId);
        String parkCode=tbParkspace.getParkCode();
        return getParkStatus(supplierId,parkId);
    }

    public ParkStatu getParkStatus(int supplierId, String parkCode) {
        // 根据车场id对应接口
        ParkStatu status = new ParkStatu();
        try {
            ParkAdapter adapterProxy = adapterParkProxyFactory.getParkAdapter(String.valueOf(supplierId));
            AdParkInfo parkInfo= adapterProxy.getTempStopNum(parkCode,"");// 查询实时车场临停车位数
            int tempStopNum =parkInfo.getRestSpace();
            status.setTempStopNum(tempStopNum);
            status.setStatus(ParkStatuEnum.ONLINE.getCode());
            status.setRemark("在线");
            
            ParkAdapter  parkAdapter= adapterParkProxyFactory.getParkAdapter(String.valueOf(supplierId));
            AdParkConnStatu parkConnStatu=parkAdapter.getParkConnStatu(parkCode,"");
            status.setOnLineTime(parkConnStatu.getLastRequestTime());
            cacheServiceFacade.updateParkonlinetime(String.valueOf(supplierId), parkCode);
        } catch (Exception e) {
            status.setTempStopNum(-1);
            status.setStatus(ParkStatuEnum.OUTLINE.getCode());
            Date timeout = cacheServiceFacade.queryParkonlinetime(String.valueOf(supplierId),
                    parkCode);
            status.setRemark("离线");
            status.setOnLineTime(timeout);
            exceptionHandle.handle(e);
        }
        return status;
    }


    /*
     * (非 Javadoc) Description:
     * @see com.qding.park.manager.facade.core.service.ParkFacade#getParkings(java. lang.String, java.lang.String) 说明:
     * １、根据用户id和手机号从数据库查询 关联的车场列表 2、查询车场软件供应商信息 2、根据车场信息可以知道车场软件供应商类型 及接口地址，通过接口地址查询车场的实时信息 ３、拼装报文返回
     */
    @Override
    public ParkDataResult getParkings(String bjuserid, long phone, String projectId) throws BaseException {

        _log.debug("ParkTempStopNumReserve=" + ParkTempStopNumReserve.getPark_tempStopNum_reserve());
        _log.debug("ExpiratAdvanceWarn=" + ExpiratAdvanceWarn.getExpirat_advance_warn());

        /* 注册用户 */
        TbUserInfo u = new TbUserInfo();
        u.setTel(phone);
        u.setBjCode(bjuserid);
        u.setUserType(UserTypeEnum.REGISTER_USER.getType());
        TbUserInfo tbUserInfo = userDBAtomic.register_loginUser(u);
        if (tbUserInfo.getUserType() != UserTypeEnum.REGISTER_USER.getType()) {
            throw new ServiceCoreException(ServiceCoreException.TypeEnum.EXCEPTION_NO_DATA_INVALID.getId(), null,
                    ExceptionMessage.createExceptionMessage(
                            ServiceCoreException.TypeEnum.EXCEPTION_NO_DATA_INVALID.getDesc(), "请联络物业管理处更新登记车辆时预留的手机号",
                            " phone=" + phone + ",bjuserId=" + bjuserid));
        }
        int userId = tbUserInfo.getId();// 用户id
        List<TbParkspace> parkList = tbParkspaceMapper.queryParksByUserId(userId);
        /* 注册用户 */

        if (!ListUtil.isEmpty(parkList) && !StringUtils.isBlank(projectId)) {
            for (TbParkspace park : parkList) {
                int parkId = park.getId();
                TbParkspace tempParkspace = parkCacheInter.queryParkSpace(parkId);
                park.setBjprojectId(tempParkspace.getBjprojectId());
            }

            List<TbParkspace> temp = null;
            // 排序 将与project相匹配的id 放在前面
            for (int i = 0; i < parkList.size(); i++) {
                for (int j = parkList.size() - 1; j > i; j--) {

                    if (projectId.equals(parkList.get(j).getBjprojectId())) {
                        TbParkspace temp_1 = parkList.get(j - 1);
                        parkList.set(j - 1, parkList.get(j));
                        parkList.set(j, temp_1);
                    }
                }
            }

        }

        // 查询在场车辆信息
//        _log.debug(parkList);
        if (!ListUtil.isEmpty(parkList)) {
            // 组装data
            List list = new ArrayList();
            for (TbParkspace park : parkList) {
                // 查询车场实时属性
                int parkId = park.getId();
                TbParkspace parkinfo = parkBiz.getParkInfoByParkId(parkId);
                if (parkinfo == null) {
                    continue;
                }
                String parkName = parkinfo.getParkName();
                int reserveTime = parkinfo.getReserveTime();

                int supplierId = parkinfo.getSupplierId();// 车场软件供应商id
                ParkStatu parkstatus = getParkStatus(supplierId, parkinfo.getParkCode());
                Map<String, Object> map = new HashMap<String, Object>();
                map.put("parkId", parkinfo.getId());
                map.put("parkName", parkinfo.getName());
                // 设置实时的车场临停车位数 在此处要减去预留车位数
                map.put("tempStopNum",
                        parkstatus.getTempStopNum() - ParkTempStopNumReserve.getPark_tempStopNum_reserve() < 0 ? 0
                                : parkstatus.getTempStopNum() - ParkTempStopNumReserve.getPark_tempStopNum_reserve());
                map.put("bookTime", reserveTime * 60);
                map.put("parkStatus", parkstatus.getStatus());
                // if(parkstatus.getStatus()==ParkStatuEnum.ONLINE.getCode()){
                map.put("parkedCarList", new ArrayList());
                // }
                // long minCardExpiration = 0;
                if (!ListUtil.isEmpty(park.getCarList()) && parkstatus.getStatus() == ParkStatuEnum.ONLINE.getCode()) {
                    // 当在线车场在线时才返回 车辆列表
                    for (TbCar car : park.getCarList()) {
                        if (StringUtils.isBlank(car.getCarNum())
                                || (car.getCheckOutTime() == null && car.getParkID() == 0)
                                || car.getCheckOutTime() != null) {
                            continue;
                        }
                        // 此处要算出最近到到期时间
                        Map<String, Object> map1 = new HashMap<String, Object>();
                        map1.put("carNum", car.getCarNum());

                        ((List) map.get("parkedCarList")).add(map1);
                    }
                }

                Date expiration = getUserParkExpiration(userId, parkId);
                // map.put("cardExpiration",
                // expiration == null || DateUtils.addDay(new Date(), ExpiratAdvanceWarn.getExpirat_advance_warn())
                // .getTime() < expiration.getTime() ? 0 : expiration.getTime() / 1000);
                /***** 为了兼容前台版本做特殊处理 *******/
                if (StringUtil.isBlank(projectId)) {
                    map.put("cardExpiration",
                            expiration == null
                                    || DateUtils.addDay(new Date(), ExpiratAdvanceWarn.getExpirat_advance_warn())
                                            .getTime() < expiration.getTime() ? 0 : expiration.getTime() / 1000);
                } else {
                    map.put("cardExpiration", expiration == null ? 0 : expiration.getTime() / 1000);
                }
                /***** 为了兼容前台版本做特殊处理 *******/
                list.add(map);
            }
            ParkDataResult data = ParkDataResult.createListDate();
            data.putDataOnList(list);
            return data;
        } else {
            return ParkDataResult.createEmpty();
        }
        // 创建list data

    }
    
    private Date getUserParkExpiration(int userId, int parkId) {
        List<TbCar> carList = tbCarMapper.queryCarOfParkByParkIdUserId(parkId, userId);

        if (ListUtil.isEmpty(carList)) {
            return null;
        }

        Date expiration = null;

        for (TbCar car : carList) {
            if (car.getCardExpiration() == null) {
                // 如果有一个卡的到期时间是null则直接返回，因为这就是最小值了
                return null;
            }
            if (expiration == null) {
                expiration = car.getCardExpiration();
            } else {

                expiration = (expiration.getTime() < car.getCardExpiration().getTime() ? expiration
                        : car.getCardExpiration());
            }
        }
        return expiration;
    }


    @Override
    public ParkStatu getParkStatus(int parkId) {
        TbParkspace  parkspace= this.tbParkspaceMapper.queryParkInfoByParkId(parkId);
        int supplierId=parkspace.getSupplierId();
        String parkCode=parkspace.getParkCode();
        return getParkStatus(supplierId,parkCode);
    }

}
